package raft.examples;

import demo.core.RaftNode;
import demo.core.RaftState;
import demo.message.InMemoryMessageHandler;
import raft.cmd.RaftFailoverDemo;

import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

/**
 * Raft算法使用示例
 */
public class RaftExample {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== Raft算法演示 ===");

        // 创建3个节点的集群
        List<String> nodeIds = Arrays.asList("node1", "node2", "node3");

        // 为每个节点创建消息处理器
        InMemoryMessageHandler handler1 = new InMemoryMessageHandler();
        InMemoryMessageHandler handler2 = new InMemoryMessageHandler();
        InMemoryMessageHandler handler3 = new InMemoryMessageHandler();

        // 创建节点
        RaftNode node1 = new RaftNode("node1", Arrays.asList("node2", "node3"), handler1);
        RaftNode node2 = new RaftNode("node2", Arrays.asList("node1", "node3"), handler2);
        RaftNode node3 = new RaftNode("node3", Arrays.asList("node1", "node2"), handler3);

        // 注册节点到消息处理器
        InMemoryMessageHandler.registerNode("node1", node1);
        InMemoryMessageHandler.registerNode("node2", node2);
        InMemoryMessageHandler.registerNode("node3", node3);

        System.out.println("\n所有节点已启动，等待领导者选举...");

        // 等待选举完成
        Thread.sleep(2000);

        // 显示集群状态
        printClusterStatus(node1, node2, node3);

        // 找到领导者
        RaftNode leader = findLeader(node1, node2, node3);
        if (leader != null) {
            System.out.println("\n开始添加日志条目...");

            // 添加一些日志条目
            leader.appendEntry("SET key1=value1");
            Thread.sleep(500);
            leader.appendEntry("SET key2=value2");
            Thread.sleep(500);
            leader.appendEntry("DELETE key1");
            Thread.sleep(500);

            printClusterStatus(node1, node2, node3);

            // 交互式命令
            System.out.println("\n=== 交互式模式 ===");
            System.out.println("输入命令 (例如: SET key=value, GET key, DELETE key)");
            System.out.println("输入 'status' 查看集群状态");
            System.out.println("输入 'failover' 演示基本故障转移");
            System.out.println("输入 'complex' 演示复杂故障转移场景");
            System.out.println("输入 'exit' 退出");

            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.print("> ");
                String command = scanner.nextLine().trim();

                if ("exit".equalsIgnoreCase(command)) {
                    break;
                } else if ("status".equalsIgnoreCase(command)) {
                    printClusterStatus(node1, node2, node3);
                } else if ("failover".equalsIgnoreCase(command)) {
                    System.out.println("启动基本故障转移演示...");
                    // 先关闭当前集群
                    node1.shutdown();
                    node2.shutdown();
                    node3.shutdown();

                    // 运行故障转移演示
                    try {
                        RaftFailoverDemo.demonstrateFailoverDuringLogSync();
                    } catch (Exception e) {
                        System.err.println("故障转移演示失败: " + e.getMessage());
                    }
                    break;
                } else if ("complex".equalsIgnoreCase(command)) {
                    System.out.println("启动复杂故障转移场景演示...");
                    // 先关闭当前集群
                    node1.shutdown();
                    node2.shutdown();
                    node3.shutdown();

                    // 运行复杂故障转移演示
                    try {
                        RaftFailoverDemo.demonstrateComplexFailoverScenario();
                    } catch (Exception e) {
                        System.err.println("复杂故障转移演示失败: " + e.getMessage());
                    }
                    break;
                } else if (!command.isEmpty()) {
                    RaftNode currentLeader = findLeader(node1, node2, node3);
                    if (currentLeader != null) {
                        boolean success = currentLeader.appendEntry(command);
                        if (success) {
                            System.out.println("命令已提交到领导者");
                        } else {
                            System.out.println("提交失败，请重试");
                        }
                        Thread.sleep(300); // 等待日志复制
                    } else {
                        System.out.println("没有找到领导者，请稍后重试");
                    }
                }
            }
            scanner.close();
        } else {
            System.out.println("没有选出领导者！");
        }

        // 关闭所有节点
        System.out.println("\n关闭集群...");
        node1.shutdown();
        node2.shutdown();
        node3.shutdown();

        System.out.println("演示结束");
    }

    private static void printClusterStatus(RaftNode... nodes) {
        System.out.println("\n=== 集群状态 ===");
        for (RaftNode node : nodes) {
            String status = node.getStatus();
            String role = node.getState() == RaftState.LEADER ? " (LEADER)" : "";
            System.out.println(status + role);
        }
        System.out.println("==================");
    }

    private static RaftNode findLeader(RaftNode... nodes) {
        for (RaftNode node : nodes) {
            if (node.getState() == RaftState.LEADER) {
                return node;
            }
        }
        return null;
    }

    /**
     * 模拟节点故障
     */
    public static void simulateNodeFailure() throws InterruptedException {
        System.out.println("\n=== 节点故障模拟 ===");

        List<String> nodeIds = Arrays.asList("node1", "node2", "node3", "node4", "node5");

        // 创建5个节点的集群
        RaftNode[] nodes = new RaftNode[5];
        for (int i = 0; i < 5; i++) {
            String nodeId = "node" + (i + 1);
            List<String> peers = nodeIds.stream()
                    .filter(id -> !id.equals(nodeId))
                    .collect(java.util.stream.Collectors.toList());

            nodes[i] = new RaftNode(nodeId, peers, new InMemoryMessageHandler());
            InMemoryMessageHandler.registerNode(nodeId, nodes[i]);
        }

        // 等待选举
        Thread.sleep(3000);
        printClusterStatus(nodes);

        // 找到领导者并添加一些日志
        RaftNode leader = findLeader(nodes);
        if (leader != null) {
            System.out.println("\n添加日志到集群...");
            for (int i = 0; i < 5; i++) {
                leader.appendEntry("Command " + i);
                Thread.sleep(200);
            }

            printClusterStatus(nodes);

            // 模拟领导者故障
            System.out.println("\n模拟领导者故障...");
            String failedLeaderId = leader.getNodeId();
            leader.shutdown();
            InMemoryMessageHandler.unregisterNode(failedLeaderId);

            // 等待新的选举
            Thread.sleep(3000);
            System.out.println("\n故障后的集群状态:");
            for (RaftNode node : nodes) {
                if (!node.getNodeId().equals(failedLeaderId)) {
                    System.out.println(node.getStatus());
                }
            }
        }

        // 清理
        for (RaftNode node : nodes) {
            if (node != leader) {
                node.shutdown();
            }
        }
    }
} 